package edu.cornell.cubooks.dao.impl;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.transaction.annotation.Transactional;

import edu.cornell.cubooks.CUBooksConstants;
import edu.cornell.cubooks.dao.PostingDao;
import edu.cornell.cubooks.domain.Bid;
import edu.cornell.cubooks.domain.Posting;
import edu.cornell.cubooks.domain.User;
import static edu.cornell.cubooks.CUBooksConstants.*;

@Transactional
public class PostingDaoImpl extends GenericDaoImpl<Posting, Integer> implements PostingDao {
	
	/*
	 * (non-Javadoc)
	 * @see edu.cornell.cubooks.dao.BookDao#getMine(edu.cornell.cubooks.domain.User)
	 */
	@SuppressWarnings("unchecked")
	public Set<Posting> getMine(User user) {
		
		List<Posting> postings = (List<Posting>) sessionFactory.getCurrentSession()
			.createCriteria(domainClass)
			.add(Restrictions.eq("user", user))
			.list();
		return toSet(postings);
	}

	/*
	 * (non-Javadoc)
	 * @see edu.cornell.cubooks.dao.PostingDao#closePosting(edu.cornell.cubooks.domain.Posting)
	 */
	public boolean isClosable(Posting posting) {
		java.sql.Date now = new java.sql.Date(new java.util.Date().getTime());
		
		// if posting is not already closed
		if (posting.getStatus() != STATUS_CLOSE) {
			// the ending date is lower than now
			if (posting.getEndDate() != null && now.after(posting.getEndDate())) {
				return true;
			}
		}
		return false;
	}
	
	/*
	 * (non-Javadoc)
	 * @see edu.cornell.cubooks.dao.PostingDao#close(edu.cornell.cubooks.domain.Posting)
	 */
	public Posting close(Posting posting) {
		
		// set status to closed
		posting.setStatus(STATUS_CLOSE);
			
		// if biding is set
		if (posting.getBids().size() > 0) {
			// take highest biding from the list
			Bid bid = (Bid) posting.getBids().iterator().next();
				
			if (bid != null) {
				// update winner
				posting.setWinner(bid.getUser());
				
			}
		}
		
		this.update(posting);
		return posting;
	}
	
	/*
	 * (non-Javadoc)
	 * @see edu.cornell.cubooks.dao.PostingDao#getAllByStatus(int)
	 */
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = false)
	public Set<Posting> getAllByStatus(int status) {
		List<Posting> postings = (List<Posting>) sessionFactory.getCurrentSession()
			.createCriteria(domainClass)
			.add(Restrictions.eq("status", status))
			.list();
		return toSet(postings);
	}
	
	/*
	 * (non-Javadoc)
	 * @see edu.cornell.cubooks.dao.PostingDao#getAllBySearchTitle(java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = false)
	public Set<Posting> getAllBySearchTitle(String title) {
		List<Posting> postings = (List<Posting>) sessionFactory.getCurrentSession()
			.createCriteria(domainClass)
			.add(Restrictions.like("title", "%"+title+"%"))
			.add(Restrictions.eq("status", CUBooksConstants.STATUS_ACTIVE))
			.list();
		return toSet(postings);
	}
	
	/*
	 * (non-Javadoc)
	 * @see edu.cornell.cubooks.dao.PostingDao#getAllByUserBids(edu.cornell.cubooks.domain.User)
	 */
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = false)
	public Set<Posting> getAllByUserBids(User user) {
		Criteria crit = sessionFactory.getCurrentSession().createCriteria(domainClass);
		crit.createCriteria("bids").add(Restrictions.eq("user", user)); // Option of Account class
		List<Posting> postings = crit.list();
		return toSet(postings);
	}
	
	/*
	 * (non-Javadoc)
	 * @see edu.cornell.cubooks.dao.PostingDao#closeAll(java.util.Set)
	 */
	public Set<Posting> closeAll(Set<Posting> postings) {
		Set<Posting> postingSet = Collections.synchronizedSet(postings);
		// synchronize before looping to avoid java.util.ConcurrentModificationException
		synchronized(postingSet) {
			Iterator<Posting> i = postings.iterator();
		    while (i.hasNext()) {
		    	Posting posting = i.next();
		    	if (isClosable(posting)) {
					close(posting);
		    	}
		    }
		}
		
		return postings;
	}


}
